home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / gnulib / libsrc98.zoo / ndoprnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-24  |  22.0 KB  |  931 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. /*
  19.  * minorly customized for gcc lib
  20.  *    ++jrb
  21.  * and for the sfp004 as well as the TT's 68881
  22.  *      mjr++
  23.  * and for turbo C and the MiNT library
  24.  *     ++um,mh
  25.  * bugfixes + ieee double extended support (new float conversion
  26.  * routine that can cope with very large/small numbers)
  27.  *     ++bm
  28.  */
  29.  
  30. #ifndef __NO_FLOAT__
  31. # define __FLOATS__ 1
  32. #endif
  33.  
  34. #ifdef LIBC_SCCS
  35. static char sccsid[] = "@(#)doprnt.c    5.37 (Berkeley) 3/26/89";
  36. #endif /* LIBC_SCCS */
  37.  
  38. #include <compiler.h>
  39. #ifdef __TURBOC__
  40. #include <sys\types.h>
  41. #else
  42. #include <sys/types.h>
  43. #endif
  44. #include <stdarg.h>
  45. #include <stdio.h>
  46. #include <ctype.h>
  47. #include <string.h>
  48. #include <limits.h>
  49. #include <math.h>    /* mjr++    */
  50.  
  51. #ifdef __FLOATS__
  52. # include "flonum.h"
  53. static void cvt __PROTO((double, short, short, short, char *, short *,
  54.     char *, short *, char *, short *, short *, char *, short *,
  55.     short *, char *));
  56.  
  57. # if defined __IEEE_DOUBLE_REAL__ /* 64 bits */
  58. #  define NAN_HI  0x7fffffffL
  59. #  define NAN2_HI 0xffffffffL /* the sign may be negative */
  60. #  define NAN_LO  0xffffffffL
  61.  
  62. #  define INF_HI  0x7ff00000L
  63. #  define INF_LO  0x00000000L
  64.  
  65. #  define MAXEXP 308  /* 11 bit exponent => 308 decimal digits */
  66. #  define MAXEXPLEN 3 /* length of the exponent itself (00..308) */
  67. #  define MAXFRACT 15 /* 53 bit fraction => max. 15 decimal digits */
  68.  
  69. # elif defined __IEEE_DOUBLE_EXTENDED__ /* 80 bits */
  70. #  define NAN_HI  0x7fffffffL
  71. #  define NAN2_HI 0xffffffffL /* the sign may be negative */
  72. #  define NAN_LO  0xffffffffL
  73. #  define NAN_80  0xffff
  74.  
  75. #  define INF_HI  0x7fff0000L
  76. #  define INF_LO  0x00000000L
  77. #  define INF_80  0x0000
  78.  
  79. #  define MAXEXP 4932 /* 15 bit exponent => 4932 decimal digits */
  80. #  define MAXEXPLEN 4 /* length of the exponent itself (00..4932) */
  81. #  define MAXFRACT 19 /* 64 bit fraction => 19 decimal digits */
  82.  
  83. # else
  84. #  error Floating point format not specified
  85. # endif
  86. #endif /* __FLOATS__ */
  87.  
  88. #ifndef __GNUC__    /* gcc lib has these typedefs in sys/types.h */
  89. #ifndef __MINT__    /* as does the MiNT library */
  90. typedef unsigned char u_char;
  91. typedef unsigned long u_long;
  92. #endif
  93. #endif
  94.  
  95. #if defined (__M68881__) && !defined (sfp004)
  96. #  include <math-68881.h>    /* mjr: use the inline functions    */
  97. #endif    __M68881__
  98.  
  99. #define    DEFPREC        6
  100.  
  101. #define MAXINTLEN 23 /* sufficient for 64 bits as octals + prefix 0 */
  102.  
  103. #ifdef __FLOATS__
  104. # if MAXINTLEN > MAXFRACT
  105. #  define BUF MAXINTLEN
  106. # else
  107. #  define BUF MAXFRACT
  108. # endif
  109. # define BUF3 (MAXEXPLEN + 2)
  110. #else
  111. # define BUF MAXINTLEN
  112. #endif /* __FLOATS__ */
  113.  
  114. #define    PUTC(ch)     if( fputc(ch, fp) == EOF ) return EOF;
  115.  
  116. #define ARG(signtag) \
  117.     _ulong = \
  118.         flags&LONGINT ? \
  119.             (unsigned long)va_arg(argp, signtag long) : \
  120.         (flags&SHORTINT ? \
  121.             (unsigned long)(signtag short)va_arg(argp, signtag short):\
  122.             (unsigned long)va_arg(argp, signtag int))
  123.  
  124.      /* bm said:
  125.           * shorts are always promoted to ints; thus, it's `va_arg(... int)'
  126.       * for `flags&SHORTINT'!
  127.       *
  128.       * sorry dont agree, it that is the case then <stdarg.h> should take
  129.       * care of it when we say va_arg(argp, short)
  130.       */
  131.  
  132. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  133.  
  134. #define    todigit(c)    ((c) - '0')
  135. #define    tochar(n)    ((n) + '0')
  136.  
  137. #define    LONGINT        0x01        /* long integer */
  138. #define    LONGDBL        0x02        /* long double; unimplemented */
  139. #define    SHORTINT    0x04        /* short integer */
  140. #define    ALT         0x08        /* alternate form */
  141. #define    LADJUST        0x10        /* left adjustment */
  142. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  143. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  144.  
  145. #if defined(__GNUC__) && (!defined(__NO_INLINE__))
  146. #ifdef __M68020__
  147.  
  148. #define _ICONV(NUMBER, BASE, BUF)                \
  149. {                                \
  150.   long i;                            \
  151.   do                                \
  152.     {                                \
  153.       __asm__ volatile                        \
  154.     ("divull %3,%0:%1"                    \
  155.      : "=d"((long)(NUMBER)), "=d"(i)            \
  156.      : "0"((long)(NUMBER)), "d"((long)(BASE)));        \
  157.       *--(BUF) = digs[i];                    \
  158.     }                                \
  159.   while (NUMBER);                        \
  160. }
  161.  
  162. #else /* !__M68020 */
  163.  
  164. #define _ICONV(NUMBER, BASE, BUF)                 \
  165. {                                \
  166.                                 \
  167.     while((NUMBER) > 65535L)                    \
  168.     {                                \
  169.         extern unsigned long __udivsi3(); /* quot = d0, rem = d1 */ \
  170.         register long i __asm ("d1");                    \
  171.     __asm__ volatile("
  172.         movl    %3,sp@-;
  173.          movl    %2,sp@-;
  174.          jsr    ___udivsi3;
  175.          addqw    #8,sp;
  176.          movl    d0,%0"                    \
  177.              : "=r"((long)NUMBER), "=d"(i)            \
  178.          : "0"((long)NUMBER), "r"((long)BASE)        \
  179.              : "d0", "d1", "a0", "a1");            \
  180.         *--BUF = digs[i];                    \
  181.     }                                \
  182.     do                                 \
  183.     {                                \
  184.             short i;                        \
  185.         __asm__ volatile("
  186.          divu    %3,%2;
  187.          swap    %0;
  188.          movw    %0,%1;
  189.          clrw    %0;
  190.                 swap    %0"                    \
  191.              : "=d"((long)NUMBER), "=g"(i)            \
  192.          : "0"((long)NUMBER), "dm"((short)BASE));    \
  193.         *--BUF = digs[i];                    \
  194.     } while(NUMBER);                        \
  195. }
  196.  
  197. #endif /* __M68020 */
  198.  
  199. #else /* !__GNUC__ */
  200.  
  201. #define _ICONV(NUMBER, BASE, BUF)                 \
  202.   do {                                \
  203.     *--(BUF) = digs[(NUMBER) % (BASE)];                \
  204.     (NUMBER) /= (BASE);                        \
  205.   } while (NUMBER);
  206.  
  207. #endif /* __GNUC__ */
  208.  
  209.  
  210. int _doprnt(fp, fmt0, argp)
  211.     register FILE *fp;
  212.     const char *fmt0;
  213.     va_list argp;
  214. {
  215.     register const u_char *fmt;    /* format string */
  216.     register int ch;    /* character from fmt */
  217.     register int cnt;    /* return value accumulator */
  218.     register int n;        /* random handy integer */
  219.     register char *t;    /* buffer pointer */
  220. #ifdef    __FLOATS__
  221. /*    double _double;        *//* double precision arguments %[eEfgG] */
  222.     union double_di _dd;    /* _double is #defined to be _dd later on */
  223.     char softsign;        /* temporary negative sign for floats */
  224. #endif    __FLOATS__
  225.     u_long _ulong;        /* integer arguments %[diouxX] */
  226.     short base;        /* base for [diouxX] conversion */
  227.     short dprec;        /* decimal precision in [diouxX] */
  228.     short fieldsz;        /* field size expanded by sign, etc */
  229.     short flags;        /* flags as above */
  230.     short prec;        /* precision from format (%.3d), or -1 */
  231.     short realsz;        /* field size expanded by decimal precision */
  232.     short size;        /* size of converted field or string */
  233.     short width;        /* width from format (%8d), or 0 */
  234.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  235.     char *digs;        /* digits for [diouxX] conversion */
  236.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  237. #ifdef __FLOATS__
  238.     short floatflag;    /* indicates floating point conversion */
  239.         /* output for f.p.:
  240.          *  string buf (size bytes)
  241.          *  zero1 * '0'
  242.          *  '.' if point is set
  243.          *  zero2 * '0'
  244.          *  string buf2 (size2 bytes)
  245.          *  zero3 * '0'
  246.          *  string buf3 (size3 bytes) (exponent)
  247.          */
  248.     short zero1;
  249.     char point;
  250.     short zero2;
  251.     short size2;
  252.     char buf2[BUF];
  253.     short zero3;
  254.     short size3;
  255.     char buf3[BUF3];
  256. #endif
  257.  
  258.         t = buf;
  259.     fmt = (const u_char *) fmt0;
  260.     digs = "0123456789abcdef";
  261.     for (cnt = 0;; ++fmt) {
  262.         if ((ch = *fmt) == 0)
  263.             return (cnt);
  264.         if (ch != '%') {
  265.             PUTC(ch);
  266.             cnt++;
  267.             continue;
  268.         }
  269. #ifdef __FLOATS__
  270.         floatflag = 0;
  271. #endif
  272.         flags = 0; dprec = 0; width = 0;
  273.         prec = -1;
  274.         sign = '\0';
  275.  
  276. rflag:        switch (*++fmt) {
  277.         case ' ':
  278.             /*
  279.              * ``If the space and + flags both appear, the space
  280.              * flag will be ignored.''
  281.              *    -- ANSI X3J11
  282.              */
  283.             if (!sign)
  284.                 sign = ' ';
  285.             goto rflag;
  286.         case '#':
  287.             flags |= ALT;
  288.             goto rflag;
  289.         case '*':
  290.             /*
  291.              * ``A negative field width argument is taken as a
  292.              * - flag followed by a  positive field width.''
  293.              *    -- ANSI X3J11
  294.              * They don't exclude field widths read from args.
  295.              */
  296.             if ((width = (short)(va_arg(argp, int))) >= 0)
  297.                 goto rflag;
  298.             width = -width;
  299.             /* FALLTHROUGH */
  300.         case '-':
  301.             flags |= LADJUST;
  302.             goto rflag;
  303.         case '+':
  304.             sign = '+';
  305.             goto rflag;
  306.         case '.':
  307.             if (*++fmt == '*')
  308.                 n = va_arg(argp, int);
  309.             else {
  310.                 n = 0;
  311.                 while (isascii(*fmt) && isdigit(*fmt))
  312.                     n = TEN_MUL(n) + todigit(*fmt++);
  313.                 --fmt;
  314.             }
  315.             prec = n < 0 ? -1 : n;
  316.             goto rflag;
  317.         case '0':
  318.             /*
  319.              * ``Note that 0 is taken as a flag, not as the
  320.              * beginning of a field width.''
  321.              *    -- ANSI X3J11
  322.              */
  323.             flags |= ZEROPAD;
  324.             goto rflag;
  325.         case '1': case '2': case '3': case '4':
  326.         case '5': case '6': case '7': case '8': case '9':
  327.             n = 0;
  328.             do {
  329.                 n = TEN_MUL(n) + todigit(*fmt);
  330.             } while (isascii(*++fmt) && isdigit(*fmt));
  331.             width = n;
  332.             --fmt;
  333.             goto rflag;
  334.         case 'L':
  335.             flags |= LONGDBL;
  336.             goto rflag;
  337.         case 'h':
  338.             flags |= SHORTINT;
  339.             goto rflag;
  340.         case 'l':
  341.             flags |= LONGINT;
  342.             goto rflag;
  343.         case 'c':
  344.             *(t = buf) = va_arg(argp, int);
  345.             size = 1;
  346.             sign = '\0';
  347.             goto pforw;
  348.         case 'D':
  349.             flags |= LONGINT;
  350.             /*FALLTHROUGH*/
  351.         case 'd':
  352.         case 'i':
  353.             ARG(signed);
  354.             if ((long)_ulong < 0) {
  355.                 _ulong = -_ulong;
  356.                 sign = '-';
  357.             }
  358.             base = 10;
  359.             goto number;
  360. #ifdef __FLOATS__
  361.         case 'e':
  362.         case 'E':
  363.         case 'f':
  364.         case 'g':
  365.         case 'G':
  366.  
  367. #define    _double _dd.d
  368.             _double = va_arg(argp, double);
  369.  
  370. /* mjr: check for NANs */
  371.             if (_dd.i[0] == NAN_HI || _dd.i[0] == NAN2_HI) {
  372.                 t = buf;
  373.                 t = strcpy(t, "NaN");
  374.                 size = strlen(t);
  375.                 goto pforw;
  376.             }
  377.  
  378.             if (prec == -1)
  379.                 prec = DEFPREC;
  380.             /*
  381.              * softsign avoids negative 0 if _double is < 0 and
  382.              * no significant digits will be shown
  383.              */
  384.             if (_double < 0) {
  385.                 softsign = '-';
  386.                 _double = -_double;
  387.             }
  388.             else
  389.                 softsign = 0;
  390. /* mjr: check for +-INFINITY */
  391.             if (((unsigned long)_dd.i[0] == INF_HI) &&
  392.                 ((unsigned long)_dd.i[1] == INF_LO)
  393. #ifdef __IEEE_DOUBLE_EXTENDED__
  394.                 && ((unsigned int)_dd.j[4] == INF_80)
  395. #endif
  396.                 ) {
  397.                 t = buf;
  398.                 if(softsign == 0)
  399.                 t = strcpy(t, "+Inf");
  400.                 else
  401.                 t = strcpy(t, "-Inf");
  402.                 size = strlen(t);
  403.                 goto pforw;
  404.             }
  405.             floatflag = 1;
  406.  
  407.             cvt(_double, prec, flags, (int) *fmt,
  408.                 &softsign, &size, buf, &zero1, &point,
  409.                 &zero2, &size2, buf2, &zero3, &size3, buf3);
  410.             t = buf;
  411.  
  412.             /*
  413.              * softsign is set to 0 by cvt if the value
  414.              * becomes 0 by rounding
  415.              */
  416.             if (softsign)
  417.                 sign = '-';
  418.             goto pforw;
  419. #endif /* __FLOATS__ */
  420.         case 'n':
  421.             if (flags & LONGINT)
  422.                 *va_arg(argp, long *) = cnt;
  423.             else if (flags & SHORTINT)
  424.                 *va_arg(argp, short *) = cnt;
  425.             else
  426.                 *va_arg(argp, int *) = cnt;
  427.             break;
  428.         case 'O':
  429.             flags |= LONGINT;
  430.             /*FALLTHROUGH*/
  431.         case 'o':
  432.             ARG(unsigned);
  433.             base = 8;
  434.             goto nosign;
  435.         case 'p':
  436.             /*
  437.              * ``The argument shall be a pointer to void.  The
  438.              * value of the pointer is converted to a sequence
  439.              * of printable characters, in an implementation-
  440.              * defined manner.''
  441.              *    -- ANSI X3J11
  442.              */
  443.             /* NOSTRICT */
  444.             _ulong = (u_long)va_arg(argp, void *);
  445.             base = 16;
  446.             goto nosign;
  447.         case 's':
  448.             if ((t = va_arg(argp, char *)) == 0)
  449.                 t = "(null)";
  450.             if (prec >= 0) {
  451.                 /*
  452.                  * can't use strlen; can only look for the
  453.                  * NUL in the first `prec' characters, and
  454.                  * strlen() will go further.
  455.                  */
  456. #ifdef __STDC__
  457.                 char *p;
  458.                 void *memchr(const void *, int, size_t);
  459. #else
  460.                 char *p, *memchr();
  461. #endif
  462.  
  463.                 if ((p = (char *)memchr(t, 0, (size_t)prec))
  464.                     != NULL) {
  465.                     size = p - t;
  466.                     if (size > prec)
  467.                         size = prec;
  468.                 } else
  469.                     size = prec;
  470.             } else
  471.                 size = (int)strlen(t);
  472.             sign = '\0';
  473.             goto pforw;
  474.         case 'U':
  475.             flags |= LONGINT;
  476.             /*FALLTHROUGH*/
  477.         case 'u':
  478.             ARG(unsigned);
  479.             base = 10;
  480.             goto nosign;
  481.         case 'X':
  482.             digs = "0123456789ABCDEF";
  483.             /* FALLTHROUGH */
  484.         case 'x':
  485.             ARG(unsigned);
  486.             base = 16;
  487.             /* leading 0x/X only if non-zero */
  488.             if (flags & ALT && _ulong != 0)
  489.                 flags |= HEXPREFIX;
  490.  
  491.             /* unsigned conversions */
  492. nosign:            sign = '\0';
  493.             /*
  494.              * ``... diouXx conversions ... if a precision is
  495.              * specified, the 0 flag will be ignored.''
  496.              *    -- ANSI X3J11
  497.              */
  498. number:            if ((dprec = prec) >= 0)
  499.                 flags &= ~ZEROPAD;
  500.  
  501.             /*
  502.              * ``The result of converting a zero value with an
  503.              * explicit precision of zero is no characters.''
  504.              *    -- ANSI X3J11
  505.              */
  506.             t = buf + BUF;
  507.             if (_ulong != 0 || prec != 0) {
  508.                 _ICONV(_ulong, base, t);
  509.                 digs = "0123456789abcdef";
  510.                 if (flags & ALT && base == 8 && *t != '0')
  511.                     *--t = '0'; /* octal leading 0 */
  512.             }
  513.             size = buf + BUF - t;
  514.  
  515. pforw:
  516.             /*
  517.              * All reasonable formats wind up here.  At this point,
  518.              * `t' points to a string which (if not flags&LADJUST)
  519.              * should be padded out to `width' places.  If
  520.              * flags&ZEROPAD, it should first be prefixed by any
  521.              * sign or other prefix; otherwise, it should be blank
  522.              * padded before the prefix is emitted.  After any
  523.              * left-hand padding and prefixing, emit zeroes
  524.              * required by a decimal [diouxX] precision, then print
  525.              * the string proper. For floating values: This string
  526.              * is followed by '0's, the decimal point if required,
  527.              * again '0's, a second string, once more '0's and a
  528.              * third string (the exponent). Finally, if LADJUST,
  529.              * pad with blanks.
  530.              */
  531.  
  532.             /*
  533.              * compute actual size, so we know how much to pad
  534.              * fieldsz excludes decimal prec; realsz includes it
  535.              */
  536. #ifdef __FLOATS__
  537.             if (floatflag != 0)
  538.                 fieldsz = size + zero1 + (point != 0)
  539.                     + zero2 + size2 + zero3 + size3;
  540.             else
  541. #endif
  542.                 fieldsz = size;
  543.             if (sign)
  544.                 fieldsz++;
  545.             if (flags & HEXPREFIX)
  546.                 fieldsz += 2;
  547.             realsz = dprec > fieldsz ? dprec : fieldsz;
  548.  
  549.             /* right-adjusting blank padding */
  550.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  551.                 for (n = realsz; n < width; n++)
  552.                     PUTC(' ');
  553.             /* prefix */
  554.             if (sign)
  555.                 PUTC(sign);
  556.             if (flags & HEXPREFIX) {
  557.                 PUTC('0');
  558.                 PUTC((char)*fmt);
  559.             }
  560.             /* right-adjusting zero padding */
  561.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  562.                 for (n = realsz; n < width; n++)
  563.                     PUTC('0');
  564.             /* leading zeroes from decimal precision */
  565.             for (n = fieldsz; n < dprec; n++)
  566.                 PUTC('0');
  567.  
  568.             /* the string or number proper */
  569.             for (n = size; --n >= 0; )
  570.                 PUTC(*t++);
  571. #ifdef __FLOATS__
  572.             if (floatflag != 0) {
  573.                 while (--zero1 >= 0)
  574.                     PUTC('0');
  575.                 if (point != 0)
  576.                     PUTC('.');
  577.                 while (--zero2 >= 0)
  578.                     PUTC('0');
  579.                 t = buf2;
  580.                 while (--size2 >= 0)
  581.                     PUTC(*t++);
  582.                 while (--zero3 >= 0)
  583.                     PUTC('0');
  584.                 t = buf3;
  585.                 while (--size3 >= 0)
  586.                     PUTC(*t++);
  587.             }
  588. #endif /* __FLOATS__ */
  589.             /* left-adjusting padding (always blank) */
  590.             if (flags & LADJUST)
  591.                 for (n = realsz; n < width; n++)
  592.                     PUTC(' ');
  593.             /* finally, adjust cnt */
  594.             cnt += width > realsz ? width : realsz;
  595.             break;
  596.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  597.             return (cnt);
  598.         default:
  599.             PUTC((char)*fmt);
  600.             cnt++;
  601.         }
  602.     }
  603.     /* NOTREACHED */
  604. }
  605.  
  606. #ifdef __FLOATS__
  607.  
  608. static int double2decimal __PROTO((double, char *, char *));
  609.  
  610. void cvt(number, prec, flags, fmtch,
  611.         sign, size1, output1, zero1, point, zero2,
  612.         size2, output2, zero3, size3, output3)
  613.     double number;
  614.     short  prec, flags, fmtch;
  615.     char   *sign, *point;
  616.     short  *zero1, *zero2, *zero3;
  617.     short  *size1, *size2, *size3;
  618.     char   *output1, *output2, *output3;
  619. {
  620.     /* new floating point conversion routine, ++bm
  621.      *
  622.      * The output consists of several parts that _doprnt has to
  623.      * put together:
  624.      *   - *sign (it is set to '\0' if the number becomes 0 by rounding)
  625.      *   - string output1 with length *size1
  626.      *   - *zero1 '0's
  627.      *   - *point (it is set to '\0' or '.')
  628.      *   - *zero2 '0's
  629.      *   - string output2 with length *size2
  630.      *   - *zero3 '0's
  631.      *   - string output3 with length *size3
  632.      */
  633.  
  634.         /* additional bytes: 1 at the beginning,
  635.          * 1 at the end (for rounding) */
  636. #define MANTLEN (MAXFRACT + 2)
  637.     char mantstr[MANTLEN];
  638.     char *mant;
  639.     short exp10;
  640.     short roundprec;
  641.  
  642.     exp10 = (short) double2decimal(number, mantstr, mantstr + MANTLEN);
  643.  
  644.     /* mantstr should start with '0', example: if number was 1234.0,
  645.      * manstr is "0123400"... and exp10 is 3
  646.      */
  647.  
  648.     /* make roundprec the number of significant digits we need */
  649.     switch (fmtch) {
  650.         case 'f':
  651.             /* prec is the number of fraction digits */
  652.             roundprec = (exp10 + 1) + prec;
  653.             if (roundprec < 0)
  654.                 /*
  655.                  * f.p. value is too small,
  656.                  * no significant digits
  657.                  */
  658.                 roundprec = 0;
  659.             break;
  660.  
  661.         case 'g':
  662.         case 'G':
  663.             /* prec is the number of significant digits */
  664.             if (prec == 0) prec++;
  665.             roundprec = prec;
  666.             break;
  667.  
  668.         case 'e':
  669.         case 'E':
  670.             /* prec is the number of fraction digits in d.dddEdd */
  671.             roundprec = prec + 1;
  672.     }
  673.     if (roundprec > MAXFRACT)
  674.         roundprec = MAXFRACT;
  675.  
  676.     /* now round */
  677.     {
  678.         char *tmp = mantstr + roundprec + 1;
  679.         /* tmp points to a digit that we don't need */
  680.         if (*tmp >= '5') {
  681.             do {
  682.                 /* necessary if a '9' was incremented */
  683.                 *tmp = '0';
  684.                 (*--tmp)++;
  685.             } while (*tmp > '9');
  686.         }
  687.     }
  688.  
  689.     if (mantstr[0] > '0') {
  690.         /* one more digit because of rounding */
  691.         if (roundprec == 0) { /* only possible for %f */
  692.             if (exp10 + 1 + prec == 0) {
  693.                 /* see above: roundprec = ... */
  694.                 roundprec++;
  695.                 mant = mantstr;
  696.                 exp10++;
  697.             }
  698.             else {
  699.                 /* the number is too small */
  700.                 *sign = '\0';
  701.                 exp10 = 0;
  702.             }
  703.         }
  704.         else {
  705.             mant = mantstr;
  706.             exp10++;
  707.         }
  708.     }
  709.     else {
  710.         /* maybe there's nothing left now? */
  711.         char *tmp;
  712.         for (tmp = mantstr + roundprec; *tmp == '0'; tmp--) {
  713.             if (tmp == mantstr) {
  714.                 /* after rounding, 0.0 is left */
  715.                 *sign = '\0';
  716.                 roundprec = 0;
  717.                 /* the string of digits is not needed */
  718.                 exp10 = 0;
  719.                 break;
  720.             }
  721.         }
  722.         mant = mantstr + 1; /* the leading '0' is not needed */
  723.     }
  724.  
  725.     /* now mant points to a string of roundprec digits */
  726.  
  727.     if (fmtch == 'g' || fmtch == 'G') {
  728.         short significdig = prec;
  729.  
  730.         if (!(flags & ALT)) {
  731.             /* cut off trailing zeros */
  732.             char *tmp;
  733.  
  734.             /*
  735.              * if the f.p. is 0.0, roundprec == 0,
  736.              * so loop isn't executed
  737.              */
  738.             for (tmp = mant+roundprec-1;
  739.                  tmp >= mant && *tmp == '0'; tmp--)
  740.                 roundprec--;
  741.             significdig = roundprec;
  742.             /*
  743.              * before, significdig was the max. number
  744.              * of significant digits, now it's the actual number
  745.              */
  746.         }
  747.  
  748.         if (exp10 >= -4 && exp10 < prec || roundprec == 0) {
  749.             /* format is like %f */
  750.  
  751.             /*
  752.              * significdig is the number of significant digits,
  753.              * %f prints prec fraction digits
  754.              *
  755.              * if exp10>=0, (exp10+1) is the number of digits on
  756.              * the left side of the decimal point;
  757.              * if exp10<0, -(exp10+1) is the number of zeros on
  758.              * the right side of the dec.point
  759.              */
  760.             prec = significdig - exp10 - 1;
  761.             if (prec < 0)
  762.                 /* zeros on the left side of the dec.point? */
  763.                 prec = 0;
  764.             fmtch = 'f'; /* continue as if it was %f */
  765.         }
  766.         else {
  767.             /* format is like %[eE] */
  768.  
  769.             /*
  770.              * significdig is the number of significant digits,
  771.              * for %[eE], it's the number
  772.              * of fraction digits in 1.234E3
  773.              */
  774.             prec = significdig - 1;
  775.             /*
  776.              * prec was > 0 before:
  777.              * it could only be 0 if the f.p. value was 0.0,
  778.              * and then exp10 would be 0 and this wouldn't be
  779.              * executed
  780.              */
  781.             fmtch -= 2;
  782.             /* continue as if it was %[eE] (g -> e, G -> E) */
  783.         }
  784.     } /* end of %[gG] */
  785.  
  786.     /* %[eEf] remains */
  787.     /* now distribute the number of digits and zeros to the fields */
  788.     if (fmtch == 'f') {
  789.         *size1 = exp10 + 1;
  790.         if (*size1 > roundprec)
  791.             *size1 = roundprec;
  792.         else if (*size1 < 0)
  793.             *size1 = 0;
  794.  
  795.         *zero1 = *size1 ?
  796.             exp10 + 1 - roundprec
  797.             : 1;
  798.         if (*zero1 < 0)
  799.             *zero1 = 0;
  800.         *point = (flags & ALT) || prec > 0 ? '.' : '\0';
  801.         *zero2 = -exp10 - 1;
  802.         if (*zero2 < 0)
  803.             *zero2 = 0;
  804.         *size2 = roundprec - *size1;
  805.         *zero3 = prec - *zero2 - *size2;
  806.         *size3 = 0; /* no exponent */
  807.     } /* end of %f */
  808.     else {
  809.         /* it's %[eE] */
  810.         if (roundprec == 0) {
  811.             /* f.p. value is 0 */
  812.             *size1 = 0;
  813.             *zero1 = 1;
  814.         }
  815.         else {
  816.             *size1 = 1;
  817.             *zero1 = 0;
  818.         }
  819.         *point = (flags & ALT) || prec > 0 ? '.' : '\0';
  820.         *zero2 = 0;
  821.         *size2 = roundprec - *size1;
  822.         *zero3 = prec - *size2;
  823.  
  824.         /* we need the exponent */
  825.         *output3++ = fmtch; /* 'e' or 'E' */
  826.         if (exp10 >= 0)
  827.             *output3++ = '+';
  828.         else {
  829.             *output3++ = '-';
  830.             exp10 = -exp10;
  831.         }
  832.         *size3 = 2;
  833.         {
  834.             char tmp[MAXEXPLEN];
  835.             char *p = tmp;
  836.  
  837.             /* convert exponent to digits, but reversed */
  838.             *p++ = tochar(exp10 % 10); /* at least 2 digits */
  839.             exp10 /= 10;
  840.             do {
  841.                 *p++ = tochar(exp10 % 10);
  842.                 exp10 /= 10;
  843.             } while (exp10 > 0);
  844.  
  845.             /* reverse exponent */
  846.             do {
  847.                 *output3++ = *--p;
  848.                 ++*size3;
  849.             } while (p > tmp);
  850.         }
  851.     } /* end of %[eE] */
  852.  
  853.     /* distribute digits to output fields */
  854.     {
  855.         short n;
  856.  
  857.         for (n = 0; n < *size1; n++)
  858.             *output1++ = *mant++;
  859.         for (n = 0; n < *size2; n++)
  860.             *output2++ = *mant++;
  861.     }
  862. } /* end of function cvt */
  863.  
  864. static int
  865. double2decimal(number, mant, endmant)
  866.     double number;
  867.     char *mant, *endmant;
  868. {
  869.     /*
  870.      * Convert `number' to decimal (exponent is returned)
  871.      * number must be positive!
  872.      * The string `mant' has the length endmant - mant.
  873.      *
  874.      * Example: If number == 1.23e4, mant will be set to "0123000"..
  875.      * (implicit decimal point after the second character)
  876.      * and 4 will be returned.
  877.      */
  878.     int exp2, exp10;
  879.     double intpart, fractpart;
  880.  
  881.     frexp(number, &exp2);
  882.     /* number == (0.5 .. 1.0) * 2^exp2 */
  883.     {
  884.         short tmp, t;
  885.  
  886.         tmp = (int) ((long) exp2 * 30103L / 100000L);
  887.         /* tmp == exp2 * log 2 */
  888.         t = tmp;
  889.  
  890. #if MAXEXP >= 1000
  891.         while (tmp > +1000)
  892.             {tmp -= 1000; number *= 1.0e-1000;}
  893.         while (tmp < -1000)
  894.             {tmp += 1000; number *= 1.0e+1000;}
  895. #endif
  896.         while (tmp > +100)
  897.             {tmp -= 100; number *= 1.0e-100;}
  898.         while (tmp < -100)
  899.             {tmp += 100; number *= 1.0e+100;}
  900.         while (tmp > +10)
  901.             {tmp -= 10; number *= 1.0e-10;}
  902.         while (tmp < -10)
  903.             {tmp += 10; number *= 1.0e+10;}
  904.  
  905.         exp10 = t - tmp;
  906.     }
  907.     /*
  908.      * what was the argument number before is now (number * 10^exp10)
  909.      *
  910.      * now make sure that 1 <= number < 10
  911.      */
  912.  
  913.     while (number >= 10.0)
  914.         {exp10++; number /= 10.0;}
  915.     while ((fractpart = modf(number, &intpart)) != 0.0 && intpart == 0.0)
  916.         {exp10--; number *= 10.0;}
  917.  
  918.     /* intpart is now the integer part of number (1..9 or 0) */
  919.     /* number == intpart + fractpart */
  920.  
  921.     *mant++ = tochar(((int) intpart) / 10); /* should be '0' */
  922.     *mant++ = tochar(((int) intpart) % 10);
  923.     for ( ; mant < endmant; mant++) {
  924.         fractpart = modf(10.0 * fractpart, &intpart);
  925.         *mant = tochar((int) intpart);
  926.     }
  927.  
  928.     return exp10;
  929. }
  930. #endif __FLOATS__
  931.